home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Utilities Professional 1-1500
/
Utilities Professional 1-1500 (1994)(WPD)[!].iso
/
12511500
/
var1451.dms
/
var1451.adf
/
PrinterDevice
/
PrinterDevice.doc
< prev
next >
Wrap
Text File
|
1992-04-27
|
56KB
|
1,620 lines
9 PRINTER DEVICE
9.1 INTRODUCTION
The printer device works close together with both the serial
and the parallel device. If you want to control a printer,
there are several advantages of using the printer device
instead of the serial or parallel device.
First you do not need to know to which port (serial or
parallel) the printer is connected to. The printer device will
simply look at the "Preferences" settings, and will there find
this type of information.
Secondly, since the user has specified what type of printer
is used with Preferences, the printer device will also know how
to translate the universal printer commands (listed below) into
that printers own special commands. This is very good since if
your program can handle some of the commands listed below, it
will work on most printers.
Finally, there exist a lot of special features like printing
graphics, translating foreign characters, and changing the
printer settings. All this is supported by the printer device.
9.2 PRINTER DEVICE
The printer device is, as said above, very close connected to
the serial and parallel devices. The printer device can be said
to be on a "higher level". The reason of this is that the
printer device will with help of Preferences control either
the serial or parallel device. (See illustration "Printer
Device".)
----------------
|Printer Device|
----------------
|
V
-------------
|Preferences|
-------------
| |
V V
--------------- -----------------
|Serial Device| |Parallel Device|
--------------- -----------------
| |
V V
------------- ---------------
|Serial Port| |Parallel Port|
------------- ---------------
Although the complexity of printing, the printer device is very
easy and straight forward to use. It works like all other
normal devices, and with only some extra structures and
commands a lot can be done.
9.2.1 THE PRINTER DEVICE'S REQUESTBLOCKS
As with all devices you use a request block to communicate with
the printer device. You initialize the request block as will be
described below, and then you simply send it to the device with
for example an DoIO() or SendIO() command.
Since the printer device can handle a lot of special commands
there exist three different request blocks. Which should be
used depends on what you want to do.
1. The standard request block (struct IOStdReq) should be
used for all "normal" commands.
2. The special printer command block (struct IOPrtCmdReq)
should be used when you want to send special commands to
the printer.
3. The special graphic request block (struct IODRPReq) should
be used when you want to print graphics (dump a Rastport
to a printer).
To make it easier for you the printer device can handle a union
with these three structures. This means that you only have to
bother about one singe request block. The union look like this:
union printerIO
{
struct IOStdReq ios;
struct IODRPReq iodrp;
struct IOPrtCmdReq iopc;
};
Each structure of this union will be described in more detail
below.
92.2.1.1 STANDARD REQUEST BLOCK
The printer device use a standard request block (struct
IOStdReq) for all normal commands. It looks like this: (Defined
in header file "exec/io.h". Note that you will probably only
use some of these fields, so you do not need to bother too
much about it.)
struct IOStdReq
{
struct Message io_Message;
struct Device *io_Device;
struct Unit *io_Unit;
UWORD io_Command;
UBYTE io_Flags;
BYTE io_Error;
ULONG io_Actual;
ULONG io_Length;
APTR io_Data;
ULONG io_Offset;
};
io_Message: This is the message that will be sent to your reply
port once the device has successfully or not
finished your request
io_Device: Pointer to the device which is using this request
block.
io_Unit: If the device has several units (like the Trackdisk
Device) this is a pointer to one of these units.
io_Command: It is here you set the command flag which tells the
device what you actually want to do. There exist a
lot of different commands depending on which device
you are using.
The commands can be divided into to groups. The
first group of commands is the standard device
commands like read and write. They are used by most
devices, and are defined in the same header file as
the request structure ("exec/io.h"). Se chapter 17
"Devices" for more information about these commands.
(The printer device can only handle the commands
which are marked with a star "*".)
CMD_RESET: (*) Reset the device. Removes all
queued commands and sets all fields
to the default settings.
CMD_READ: Read (collect) data from the device.
CMD_WRITE: (*) Write (send) data to the device.
CMD_UPDATE: Update the device.
CMD_CLEAR: Clears the device's own input buffer.
CMD_STOP: (*) Temporarily stops the device.
CMD_START: (*) Restarts the device after it has
been stopped.
CMD_FLUSH: (*) Removes all queued commands.
The second group contains all special device
commands. Each device chapter (18-29) contains a
complete list of each device's special commands,
together with full instructions on how to use them.
The printer device uses four special commands, but
only two of these may be used by the standard
request block: (See the other structures for more
information about the two other commands.)
PRD_RAWWRITE: Sends raw (not translated)
characters.
PRD_QUERY: Send this command if you want to
receive some information about the
printer device.
io_Flags: This flag field is used by only some of the devices.
io_Error: This field is set to 0 if the device managed to do
your request, else an error number is stored here.
Depending on which device you are using different
error messages are used. However, there exist four
standard error messages (defined in header file
"exec/errors.h"):
IOERR_OPENFAIL: Could not open the device.
IOERR_ABORTED: The request was aborted.
IOERR_NOCMD: A command that was not supported
by the device was used.
IOERR_BADLENGTH: Bad length of the command - data.
If the printer device failed to do your request, one
of these error flags is returned:
PDERR_CANCEL: User cancelled the request.
PDERR_NOTGRAPHICS: The printer which the user
has can not handle
graphics.
PDERR_BADDIMENSION: The printer dimension is
not valid.
PDERR_INTERNALMEMORY: Not enough memory for the
printer device's internal
variables.
PDERR_BUFFERMEMORY: Not enough memory for the
print buffer.
io_Actual: The number of bytes that was actually collected or
sent. If this number is not the same as the number
of bytes you wanted to collect/send, the
communication may have been interrupted.
io_Length: The number of bytes you want to send or collect.
io_Data: Pointer to where the data is which should be sent,
or pointer to where all data which is collected
should be stored.
io_Offset: Offset value used by some devices.
92.2.1.2 SPECIAL PRINTER COMMAND STRUCTURE
When you want to send special printer commands like "italics
on", "boldface off", "subscript on" etc (a complete table of
printer commands is listed below) you can do it in two ways:
(A) You send the printer command's "Escape Sequence" in the
same way you send normal text. These escape sequences will
be translated by Preferences and then sent to the printer.
(B) You send the printer command with help of a special
printer command request block (struct IOPrtCmdReq).
Both options will work equally well, but your code will look
better if you use the special IOPrtCmdReq structure. (It is
easier to understand what is happening, since escape sequences
are usually not very informative and definitely not easy to
remember.) All printer commands are also defined in the header
file "devices/printer.h", and you are therefore recommended
to use them instead of the escape sequences.
struct IOPrtCmdReq
{
struct Message io_Message;
struct Device *io_Device;
struct Unit *io_Unit;
UWORD io_Command;
UBYTE io_Flags;
BYTE io_Error;
UWORD io_PrtCommand;
UBYTE io_Parm0;
UBYTE io_Parm1;
UBYTE io_Parm2;
UBYTE io_Parm3;
};
io_Message: This is the message that will be sent to your
reply port once the device has successfully or
not finished your request
io_Device: Pointer to the printer device which is using
this request block.
io_Unit: Not used by the printer device.
io_Command: Set this field to PRD_PRTCOMMAND, and the device
will know that you want to send commands to the
printer. NOTE! The flag "PRD_PRTCOMMAND" should
only be used by IOPrtCmdReq structures!!!
io_Flags: Not used.
io_Error: This field is set to 0 if the printer device
managed to do your request, else an error number
is stored here:
PDERR_CANCEL: User cancelled the
request.
PDERR_NOTGRAPHICS: The printer which the
user has can not handle
graphics.
PDERR_BADDIMENSION: The printer dimension is
not valid.
PDERR_INTERNALMEMORY: Not enough memory for
the printer device's
internal variables.
PDERR_BUFFERMEMORY: Not enough memory for
the print buffer.
io_PrtCommand: The command you want to send to the printer. See
below for a complete list of all printer
commands. Some of the commands require extra
parameters, and these parameters should be set
in the following four fields.
io_Parm0: First parameter.
io_Parm1: Second parameter.
io_Parm2: Third parameter.
io_Parm3: Fourth parameter.
92.2.1.3 SPECIAL GRAPHIC STRUCTURE
When you want to print graphics you have to use the special
IODRPReq structure. It will dump a specified rastport (see
chapter 12 "Low Level Graphics" for more information about
rastports) to the printer. Note that this request will only
work if the user has a printer that supports graphics.
The IODRPReq structure look like this: (also defined in header
file "devices/printer.h")
struct IODRPReq
{
struct Message io_Message;
struct Device *io_Device;
struct Unit *io_Unit;
UWORD io_Command;
UBYTE io_Flags;
BYTE io_Error;
struct RastPort *io_RastPort;
struct ColorMap *io_ColorMap;
ULONG io_Modes;
UWORD io_SrcX;
UWORD io_SrcY;
UWORD io_SrcWidth;
UWORD io_SrcHeight;
LONG io_DestCols;
LONG io_DestRows;
UWORD io_Special;
};
io_Message: This is the message that will be sent to your
reply port once the device has successfully or
not finished your request
io_Device: Pointer to the printer device which is using
this request block.
io_Unit: Not used by the printer device.
io_Command: Set this field to PRD_PRTCOMMAND, and the device
will know that you want to send commands to the
printer. NOTE! The flag "PRD_PRTCOMMAND" should
only be used by IOPrtCmdReq structures!!!
io_Flags: Not used.
io_Error: This field is set to 0 if the printer device
managed to do your request, else an error number
is stored here:
PDERR_CANCEL: User cancelled the
request.
PDERR_NOTGRAPHICS: The printer which the
user has can not handle
graphics.
PDERR_BADDIMENSION: The printer dimension is
not valid.
PDERR_INTERNALMEMORY: Not enough memory for
the printer device's
internal variables.
PDERR_BUFFERMEMORY: Not enough memory for
the print buffer.
io_RastPort: Pointer to the RastPort that should be printed.
io_ColorMap: Pointer to the ColorMap structure which contains
all information about the RastPort's colours.
io_Modes: The ViewPort's display modes. The information
is used to convert the picture which will be
printed to the correct aspects. (On a low
resolution screen each pixels is equally wide as
tall. However, on a high resolution screen, each
pixel is only half as wide as it is tall. The
same applies for interlaced and non interlaced
screens.) The printer device must also know if
you want to print a "normal" picture, or a
picture with one of the special display modes
like "HAM" or "Extrahalf Brite". The following
flags may be used:
HIRES: Set this flag if you want to print a high
resolution screen. If this flag is not
set, the printer device assumes that you
are using a low resolution screen.
LACE: Set this flag if you want to print an
interlaced picture. If this flag is not
set, the printer device assumes that you
are using a non-interlaced picture.
HAM: Set this flag if you want to print a
"HAM" picture.
EXTRA_HALFBRITE: Set this flag if you want to
print an "extra halfbrite" picture.
PUALPF: Set this flag if you want to print a dual
playfields screen.
Note that the simplest way is to copy the
Viewport structure's "modes" field. You will then
not risk to forget one or more display flags.
io_SrcX: X offset of the source picture.
io_SrcY: Y offset of the source picture.
io_SrcWidth: Width of the source picture.
io_SrcHeight: Height of the source picture.
io_DestCols: Width of the printed picture. If the special
flag "SPECIAL_MILCOLS" is set, the width is in
1/1000". If the special flag "SPECIAL_FULLCOLS"
is set, this field is ignored by the printer
device. (The picture will be as wide as
possible.) Finally, if the special flag
"SPECIAL_FRACCOLS" is set this field specifies
the size as a fraction of the maximum width.
io_DestRows: Height of the printed picture. If the special
flag "SPECIAL_MILROWS" is set, the height is in
1/1000". If the special flag "SPECIAL_FULLROWS"
is set, this field is ignored by the printer
device. (The picture will be as tall as
possible.) Finally, if the special flag
"SPECIAL_FRACROWS" is set this field specifies
the size as a fraction of the maximum height.
io_Special: There exist several special graphical printing
modes. Here is a complete list of flags that may
be used:
SPECIAL_MILCOLS: If this flag is set the
"io_DestCols" field specifies
the width in 1/1000".
SPECIAL_MILROWS: If this flag is set the
"io_DestRows" field specifies
the height in 1/1000".
SPECIAL_FULLCOLS: Set this flag if you want the
width of the printed picture
to be as wide as possible.
SPECIAL_FULLROWS: Set this flag if you want the
height of the printed picture
to be as tall as possible.
SPECIAL_FRACCOLS: If this flag is set the
"io_DestCols" field specifies
the width as a fraction of
the maximum width.
SPECIAL_FRACROWS: If this flag is set the
"io_DestRows" field specifies
the height as a fraction of
the maximum height.
SPECIAL_CENTER: Set this flag if you want the
picture to be centered on the
paper.
SPECIAL_ASPECT: Set this flag if you want to
use the correct aspect ratio
of the picture. If you set
the flag "SPECIAL_FULLCOLS"
and this "SPECIAL_ASPECT"
flag the printed picture will
be as large as possible, but
still with the right aspects.
SPECIAL_DENSITY1: Set this flag if you want the
picture to be printed with
the printer's lowest
resolution.
SPECIAL_DENSITY2: Next resolution.
SPECIAL_DENSITY3: Next resolution.
SPECIAL_DENSITY4: Next resolution.
SPECIAL_DENSITY5: Next resolution.
SPECIAL_DENSITY6: Next resolution.
SPECIAL_DENSITY7: Use the printer's highest
(finest) resolution.
SPECIAL_NOFORMFEED: Set this flag if you do not
want that the paper is
ejected after each time you
have printed graphics.
SPECIAL_TRUSTME: Set this flag if you do not
want the printer to reset
any parameters while
printing.
92.2.1.4 HOW TO CREATE THE PRINTER REQUEST BLOCK
To create a printer request block, use the CreateExtIO()
function. Since there exist three different types of structures
that are needed, the printer device assumes that you are using
a union of these three structures. The union is sadly not
declared in any header file, so you have to declare it
yourself. It should look like this:
union printerIO
{
struct IOStdReq ios;
struct IODRPReq iodrp;
struct IOPrtCmdReq iopc;
};
The CreateExtIO function should always be used when you want to
create a request block which is not of the normal size
(struct IOStdReq).
Synopsis: prt_req = CreateExtIO( msg_port, size );
prt_req: (struct IORequest *) If CreateExtIO() managed to
allocate and initialize the request block it returns
a pointer to it, else the function will return NULL.
(Note that you have to do some "casting" here, since
the compiler expects that the function returns a
pointer to a normal IORequest structure, but this
function is used when you create other (larger) types
of request block. Se example for more information.)
msg_port: (struct MsgPort *) Pointer to a message port to which
the device will send a message to each time it has
completed your request.
size: The size (in bytes) of the request block. Use the
function sizeof() to find out how big the special
request block is. Example: sizeof( union printerIO );
92.2.2 OPEN THE PRINTER DEVICE
As with all devices you have to open a message port through
which the printer device can communicate with you, and allocate
a request block (a printerIO union), before you may open the
device itself.
1. Open a message port: (Since it is only our task and the
device that will use the message port, we do not need
to make it "public", hence no name. Priority should as
usual be set to 0, normal priority.)
struct MsgPort *replymp;
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
2. Allocate a request block of type printerIO union. Since
the printer request block is larger than normal request
blocks (IOStdReq structure) it must be created with
the CreateExtIO() function.
union printerIO printer_req;
printer_req = (union printerIO *)
CreateExtIO( replymp, sizeof( union printerIO ) );
if( !printer_req )
clean_up( "Not enough memory!" );
3. Once the message port and the request block have
successfully been created you may open the printer device.
UBYTE error;
/* Open the printer device: */
error = OpenDevice( "printer.device", 0, printer_req, 0 );
if( error )
clean_up( "Could not open the Printer Device!" );
9.2.3 PRINT TEXT
When the printer device has been opened you may start to send
text to the printer. When printing normal text you should use
the "IOStdReq" structure of the printerIO union. You can either
send text which will not be translated (raw text) to the
printer, or you can send text that will be translated.
The advantage of sending text that is translated by Preferences
is that the characters you send will also be the same when
printed. (Many printers have their own list of foreign
characters. And if the characters are not translated, you
never know what will be printed.)
The second reason for translating text is that "escape
sequences" (like "underline on", "boldface off", "NLQ" etc...)
will be translated into the printer's own printer commands.
If you write a program that uses "escape sequences" you know
that it will work on all printers (as long as they support
your commands). If you on the other hand send special
untranslated printer commands that are unlike for some type
of printer models, your program will not work with other
types of printers.
Raw (untranslated) text should only be used when it is really
needed (which is not very often). If you want to dump the
printers own ASCII codes it can be useful to send untranslated
characters, but otherwise I recommend you to only send
translated text.
To print text simply do like this:
1. Set the "io_Command" field to CMD_WRITE if you want the
text to be translated by Preferences. On the other hand,
if you want to send raw (untranslated) text use the
"PRD_RAWWRITE" command.
2. Set the "io_Length" field to the number of characters
(bytes) you want to send.
3. Give the "io_Data" pointer the address of your data buffer
which contains the text you want to print.
4. Now send the request to the printer device, by either a
DoIO() or SendIO() function call.
If you want to wait for the device to finish your request
before your program continues you should use the
"synchronous" command DoIO(). If you instead want to
continue to do something while the printer is working,
you should use the "asynchronous" command SendIO().
Here is an example on how to send text to the printer. This is
a synchronous request, which means the program is halted while
the printer is working.
/* Pointer to an already initialized printer request block: */
union printerIO *printer_req
/* The text we want to print: (Oh no, not that text again!) */
BYTE data[13] = "Hello world!"
/* Store any error values here: */
BYTE error;
/* We want to print some translated text: (If we want */
/* to send raw, untranslated, text we should use the */
/* "PRD_RAWWRITE" command instead of "CMD_WRITE".) */
printer_req->ios.io_Command = CMD_WRITE;
/* Give the start address of our data: */
printer_req->ios.io_Data = (APTR) data;
/* Set number of chracters that should be printed: */
/* (12 characters - bytes) */
printer_req->ios.io_Length = 12;
/* Do our request: (This is a task sleep) */
error = DoIO( printer_req );
/* Check if the request was successfully executed: */
if( error )
printf( "Problems! Error code: %d\n", error );
Here is another example, but this time we use an asynchronous
request, which means the program continues to run while the
printer is working.
/* Pointer to an already initialized printer request block: */
union printerIO *printer_req
/* The text we want to print: */
BYTE data[13] = "Hello again!"
/* Store any error values here: */
BYTE error;
/* Temporary pointer: */
union printerIO *ptr;
/* We want to print some translated text: (If we want */
/* to send raw, untranslated, text we should use the */
/* "PRD_RAWWRITE" command instead of "CMD_WRITE".) */
printer_req->ios.io_Command = CMD_WRITE;
/* Give the start address of our data: */
printer_req->ios.io_Data = (APTR) data;
/* Set number of chracters that should be printed: */
/* (12 characters - bytes) */
printer_req->ios.io_Length = 12;
/* Do our request and return immediately: */
SendIO( printer_req );
/* As long as the pointer is not pointing to */
/* the request we should stay in the loop: */
ptr = NULL;
while( ptr == NULL )
{
/* ... do something ... */
/* Well, I do not know what. */
/* Check if the request has been completed: (If the */
/* request has been completed CheckIO() will return */
/* a pointer to the request, else NULL is returned.) */
ptr = (union printerIO *) CheckIO( printer_req );
}
/* At last the request was completed! */
/* Remove the request block's message. (The ptr and */
/* printer_req are in this example identical, so it */
/* does not matter whichever you use. The parenthesis */
/* around the expression is actually unnecessary, but */
/* this looks better.) */
Remove( &(ptr->ios.io_Message.mn_Node) );
/* Check if everything is OK? */
if( ptr->ios.io_Error )
printf( "Problems while printing!\n" );
9.2.4 SEND SPECIAL COMMANDS TO THE PRINTER
Most printers can use different printing styles like underlined,
italics and boldface just to mention a few. Usually you can
use several different fonts and expand and compress the
characters, as well as setting margins, use proportional styles,
handle foreign character sets etc...
All these features are controlled by special printer commands.
Most printers have their own set of unique commands. Luckily
we do not need to know about them. We simply use a set of
universal printer commands listed below, and Preferences will
automatically translate these into the specified printer's
own commands.
There exist two ways to send the printer commands to the
printer. Either you send the "escape sequences" together with
the rest of the text, or you can send the commands with a
separate request block (struct IOPrtCmdReq). Since escape
sequences are rather difficult to remember it usually looks
better if you use the separate request block technique.
When you send a printer command with help of the request block
you should use the IOPrtCmdReq structure. You set the
io_Command field to "PRD_PRTCOMMAND", the "io_PrtCommand"
field to the command you want to send, and up to four
parameters may also be sent if needed by initializing the
"io_Parm0" to "io_Parm3" fields. Here is an example:
/* We want to send a printer command to the printer: */
printer_req->iopc.io_Command = PRD_PRTCOMMAND;
/* Set the printer command: [Underline On] */
printer_req->iopc.io_PrtCommand = aSGR4;
/* Set the parameters: */
printer_req->iopc.io_Parm0 = 0; /* Nothing */
printer_req->iopc.io_Parm1 = 0; /* Nothing */
printer_req->iopc.io_Parm2 = 0; /* Nothing */
printer_req->iopc.io_Parm3 = 0; /* Nothing */
/* Do the request: */
DoIO( printer_req );
Here is the complete list of printer commands and escape
sequences. The names are defined in header file "devices/
printer.h".
If you use the escape sequences you should send the commands
exactly as written below with one difference - you should
replace the character "n" with a (ASCII) value. To set the top
and bottom margins to 2 and 4, send the escape sequence:
"ESC[2;4r" (without quotations).
Name Command Esc Seq Function Defined by
--------------------------------------------------------------
aRIS 0 ESCc reset ISO
aRIN 1 ESC#1 initialize Amiga
aIND 2 ESCD lf ISO
aNEL 3 ESCE return,lf ISO
aRI 4 ESCM reverse lf ISO
aSGR0 5 ESC[0m normal char set ISO
aSGR3 6 ESC[3m italics on ISO
aSGR23 7 ESC[23m italics off ISO
aSGR4 8 ESC[4m underline on ISO
aSGR24 9 ESC[24m underline off ISO
aSGR1 10 ESC[1m boldface on ISO
aSGR22 11 ESC[22m boldface off ISO
aSFC 12 ESC[3nm set foreground color ISO
aSBC 13 ESC[4nm set background color ISO
aSHORP0 14 ESC[0w normal pitch DEC
aSHORP2 15 ESC[2w elite on DEC
aSHORP1 16 ESC[1w elite off DEC
aSHORP4 17 ESC[4w condensed fine on DEC
aSHORP3 18 ESC[3w condensed off DEC
aSHORP6 19 ESC[6w enlarged on DEC
aSHORP5 20 ESC[5w enlarged off DEC
aDEN6 21 ESC[6"z shadow print on DEC (sort of)
aDEN5 22 ESC[5"z shadow print off DEC
aDEN4 23 ESC[4"z doublestrike on DEC
aDEN3 24 ESC[3"z doublestrike off DEC
aDEN2 25 ESC[2"z NLQ on DEC
aDEN1 26 ESC[1"z NLQ off DEC
aSUS2 27 ESC[2v superscript on Amiga
aSUS1 28 ESC[1v superscript off Amiga
aSUS4 29 ESC[4v subscript on Amiga
aSUS3 30 ESC[3v subscript off Amiga
aSUS0 31 ESC[0v normalize the line Amiga
aPLU 32 ESCL partial line up ISO
aPLD 33 ESCK partial line down ISO
Char set: or Typface:
aFNT0 34 ESC(B US 0 DEC
aFNT1 35 ESC(R French 1 DEC
aFNT2 36 ESC(K German 2 DEC
aFNT3 37 ESC(A UK 3 DEC
aFNT4 38 ESC(E Danish 4 DEC
aFNT5 39 ESC(H Sweden 5 DEC
aFNT6 40 ESC(Y Italian 6 DEC
aFNT7 41 ESC(Z Spanish 7 DEC
aFNT8 42 ESC(J Japanese 8 Amiga
aFNT9 43 ESC(6 Norweign 9 DEC
aFNT10 44 ESC(C Danish II 10 Amiga
aPROP2 45 ESC[2p proportional on Amiga
aPROP1 46 ESC[1p proportional off Amiga
aPROP0 47 ESC[0p proportional clear Amiga
aTSS 48 ESC[n E set proportional offset ISO
aJFY5 49 ESC[5 F auto left justify ISO
aJFY7 50 ESC[7 F auto right justify ISO
aJFY6 51 ESC[6 F auto full justify ISO
aJFY0 52 ESC[0 F auto justify off ISO
aJFY3 53 ESC[3 F letter space (justify) ISO (special)
aJFY1 54 ESC[1 F word fill(auto center) ISO (special)
aVERP0 55 ESC[0z 1/8" line spacing Amiga
aVERP1 56 ESC[1z 1/6" line spacing Amiga
aSLPP 57 ESC[nt set form length n DEC
aPERF 58 ESC[nq perf skip n (n>0) Amiga
aPERF0 59 ESC[0q perf skip off Amiga
aLMS 60 ESC#9 Left margin set Amiga
aRMS 61 ESC#0 Right margin set Amiga
aTMS 62 ESC#8 Top margin set Amiga
aBMS 63 ESC#2 Bottom marg set Amiga
aSTBM 64 ESC[n;nr T&B margins DEC
aSLRM 65 ESC[n;ns L&R margin DEC
aCAM 66 ESC#3 Clear margins Amiga
aHTS 67 ESCH Set horiz tab ISO
aVTS 68 ESCJ Set vertical tabs ISO
aTBC0 69 ESC[0g Clr horiz tab ISO
aTBC3 70 ESC[3g Clear all h tab ISO
aTBC1 71 ESC[1g Clr vertical tabs ISO
aTBC4 72 ESC[4g Clr all v tabs ISO
aTBCAL L73 ESC#4 Clr all h & v tabs Amiga
aTBSAL L74 ESC#5 Set default tabs Amiga
aEXTEN D75 ESC[n"x extended commands Amiga
aRAW 76 ESC[n"r Next 'Pn' chars are raw Amiga
Suggested typefaces are:
---------------------------
0 - default typeface.
1 - Line Printer or equiv.
2 - Pica or equiv.
3 - Elite or equiv.
4 - Helvetica or equiv.
5 - Times Roman or equiv.
6 - Gothic or equiv.
7 - Script or equiv.
8 - Prestige or equiv.
9 - Caslon or equiv.
10 - Orator or equiv.
Amiga: Unique command for the Amiga.
ISO: Defined by the International Standards Organization.
DEC: Defined by Digital Equipment Corporation.
9.2.5 PRINT GRAPHICS
The printer device does not only handle text, it can also be
used to print graphics. To do this we have to use the IODRPReq
structure of the request block. We give it a pointer to a
RastPort which should be printed and sets some special values
like size, resolution etc. The rest is then automatically done.
Note that some printers does not support graphics, and thus
your request will be returned immediately with an error value
"PDERR_NOTGRAPHICS".
Here is what we have to do:
1. Set the command "PRD_DUMPRPORT".
2. Give the request block a pointer to the RastPort we want
to print.
3. We must also give the request block a pointer to a ColorMap
structure which contains the picture's colour values.
4. Tell the request block what screen "mode" the RastPort is
made for. The information is used to convert the picture
which will be printed to the correct aspects.
On a low resolution screen each pixels is equally wide as
tall. However, on a high resolution screen, each pixel is
only half as wide as it is tall. The same applies for
interlaced and non interlaced screens.
The printer device must also know if you want to print a
"normal" picture, or a picture with one of the Amiga's
special display modes like "HAM" or "Extrahalf Brite".
If you print a RastPort that is connected to a ViewPort,
you can simply copy the Viewport structure's "Modes"
field. If you have defined a RastPort that is not used
to be displayed just to be printed, set the field to 0.
5. Tell the device if the whole RastPort should be printed,
or just a part of it.
6. You must also specify how large the printed picture should
be. Note that most printers have a much higher resolution
than normal screens. You can therefore usually print a
picture that is much smaller than the screen, and still
have all details as the original.
7. Finally you can set some special graphical flags as
described above.
Here is an example:
/* Store possible error numbers here: */
BYTE error;
/* An already initialized printer request block: */
union printerIO *printer_req,
/* Pointer to a RastPort: */
struct RastPort *rp,
/* Pointer to a ColourMap: */
struct ColorMap *cm,
/* We want to dump a RastPort to the printer: */
printer_req->iodrp.io_Command = PRD_DUMPRPORT;
/* Set a pointer to the RastPort structure: */
printer_req->iodrp.io_RastPort = rp;
/* Set a pointer to the ColorMap structure: */
printer_req->iodrp.io_ColorMap = cm;
/* Set the "display" modes: */
/* (0 = aspect 1:1, normal screen.) */
printer_req->iodrp.io_Modes = 0;
/* X position of the source: (10 pixels out) */
printer_req->iodrp.io_SrcX = 10;
/* Y position of the source: (10 pixels down) */
printer_req->iodrp.io_SrcY = 10;
/* Width of the source: (100 pixels wide) */
printer_req->iodrp.io_SrcWidth = 100;
/* Height of the source: (50 pixels high) */
printer_req->iodrp.io_SrcHeight = 50;
/* The width of the printed picture: (This field is in */
/* this example ignored by the printer device since the */
/* special flag "SPECIAL_FULLCOLS" is set. Maximum width.) */
printer_req->iodrp.io_DestCols = 0;
/* The height of the printed picture: (This field is in */
/* this example also ignored by the printer device since */
/* the special flag "SPECIAL_ASPECT" is set. The height */
/* will therefore be automatically calculated.) */
printer_req->iodrp.io_DestRows = 0;
/* Set the special printing commands: (Full width and */
/* the height is automatically set so the printed picture */
/* will have the right aspects.) */
printer_req->iodrp.io_Special =
SPECIAL_FULLCOLS | SPECIAL_ASPECT;
/* Do our request: */
error = DoIO( printer_req );
/* Check if the request was successfully executed: */
if( error )
printf( "Problems while printing!\n" );
9.2.6 ERRORS
When you are using the printer device it sometimes happens
that your request was not successfully executed, and you have
encounter an error message. Usually it is easy to guess what
went wrong, but it is always good to check what really happened.
You will either receive the error message from the function you
just called (for example, DoIO() returns 0 or an error number),
or you can check the request block to see if there were any
problems. (The io_Error filed of the request block either
contains 0, which means everything is OK, or an error number.)
Here is a complete list of the printer device error messages:
PDERR_CANCEL: The user cancelled the request. If you
receive this error you should not
start new printer requests until the
user says he/she wants to print again.
It is very annoying if you have
cancelled a printout but the program
continues to write new data to the
printer. If you have issued several
asynchronous requests after each other
and you receive this message, it is
usually best to try to remove the
queued requests.
PDERR_NOTGRAPHICS: The printer which the user has can not
handle graphics.
PDERR_BADDIMENSION: The dimension of the printout is not
valid.
PDERR_INTERNALMEMORY: Not enough memory for the printer
device's internal variables.
PDERR_BUFFERMEMORY: Not enough memory for the print buffer.
While you are using the printer device it may happen that you
also receive error messages from Exec. (Exec is handling all
stuff like messages, requests, tasks and so on.) Here is
a complete list of exec error messages: (defined in the header
file "exec/errors.h")
IOERR_OPENFAIL The device (unit) could not be opened.
IOERR_ABORTED When you abort a previously started request
by calling the AbortIO() function, the
"io_Error" filed of that request is set to
"IOERR_ABORTED". If you find a request
block with this flag set, you know that
it has been aborted.
IOERR_NOCMD You tried to use a command that is not
supported by the printer device.
IOERR_BADLENGTH The length of the request was not valid.
9.2.7 CLEAN UP
As usual on the Amiga you must remember to close and return
everything you have opened or allocated. If you do not close
the printer device after you a lot of memory is wasted.
The routine is very similar to how you close the parallel
device which was described in the previous chapter.
Here is a list of what you have to do:
1. All requests you have started with SendIO() or BeginIO()
(asynchronous commands) must either have been completed
or aborted before you may close the device. It is a very
common error to forget this, and it can be hard to find
this bug. Usually the program will work fine (the command
was completed in time), but now and then your program will
crash (the command was completed after the device have
been closed).
A simple way is to abort all commands that have not
reported that they have been completed, but this is not
always good way to do it. (The last commands may be
important and should therefore not be aborted.)
If you do not want to abort the command, you should
instead wait for it to be completed. The WaitIO()
function is simple to use, and will put your program
to sleep while waiting, so no computer time is wasted.
If the request has already been completed, the function
will return immediately. WaitIO() will also remove the
message from the reply port. It is a very useful and
simple function to use, but do NOT try to wait for
a request that has not been started!
Here is an example on how to wait for a request to be
completed: (If the request already has been completed
it does not matter, WaitIO() will then simply return
immediately. Note that we do not have to remove any
messages from the reply port if we use WaitIO().)
/* Store possible error numbers here: */
UBYTE error;
/* ... */
/* Wait for the request to be completed: */
error = WaitIO( printer_req );
/* Everything OK? */
if( error )
printf( "Something went wrong!" );
/* Well, successful or not, we may now */
/* close the device! */
To abort a request, simply use the AbortIO() function:
/* Try to abort a previously started request: */
/* (Do not try to abort a request that has not */
/* been started!) */
AbortIO( printer_req );
2. When all requests have been completed or aborted you may
close the printer device. (Requests that have been started
by calling the DoIO() function have already been completed
before your program wakes up, and thus you do not need to
wait for these.)
The printer device is closed as all other devices, by
calling the CloseDevice() function. Here is an example:
/* Close the Printer Device: */
CloseDevice( printer_req );
3. You should now return all request blocks you have
allocated. The printer request block (union printerIO)
is an extended request block, and should be deleted by
the DeleteExtIO() function.
/* Deallocate the printer request block: */
DeleteExtIO( printer_req, sizeof(union printerIO) );
Note that ALL request blocks that have been allocated,
must be removed!
4. Finally you should close all message ports you have
previously opened. Simply use the DeletePort() function
as this example demonstrates:
/* Remove the replyport: */
DeletePort( replymp);
Please be careful with how your program terminates! Your
program should not only run fine, but it should also allow
other programs to run after and simultaneously. Remember that
your program must also be able to quit nice and neatly even if
it had to terminate too early because of some fatal error. The
cleaning up should only be done where it is needed, and if you
have not allocated the memory or opened the device before your
program quits, you should of course NOT try to free these
resources! If you do the Amiga will most certainly crash! Too
many programs contain this very annoying error. Make sure yours
will not be one of those.
9.3 A COMPLETE EXAMPLE
Here is a simple but complete example on how to print some
text. For more information see the Examples which are stored
together with this document.
#include <exec/types.h> /* Data types. */
#include <exec/errors.h> /* Exec error messages. */
#include <devices/printer.h> /* Printer Device. */
#include <exec/io.h> /* Standard request block. */
/* Declare how the printer request block look like: */
union printerIO
{
struct IOStdReq ios;
struct IODRPReq iodrp;
struct IOPrtCmdReq iopc;
};
/* Declare a pointer to our reply port: */
struct MsgPort *replymp = NULL;
/* Declare a pointer our printer request block: */
union printerIO *printer_req = NULL;
/* Store the printer device error here: */
UWORD printer_dever = TRUE;
/* Declare our data buffer: (25 characters) */
BYTE buffer[] = "Anders Bjerin was here...";
/* Declare our functions: */
void main();
void clean_up( STRPTR text );
void main()
{
/* Error number: */
BYTE error;
/* Get a reply port: (No name, priority 0) */
replymp = (struct MsgPort *)
CreatePort( NULL, 0 );
if( !replymp )
clean_up( "Could not create the reply port!" );
/* Create the printer request block: */
printer_req = (union printerIO *)
CreateExtIO( replymp, sizeof(union printerIO) );
if( !printer_req )
clean_up( "Not enough memory for the printer request block!" );
/* Open the Printer Device: */
printer_dever = OpenDevice( "printer.device", 0, printer_req, 0 );
if( printer_dever )
clean_up( "Could not open the Printer Device!" );
/* We want to print some text: (translated) */
printer_req->ios.io_Command = CMD_WRITE;
/* Give the start address of our data: */
printer_req->ios.io_Data = (APTR) buffer;
/* Set number of chracters that should be printed: */
printer_req->ios.io_Length = 25;
/* Do our request: */
error = DoIO( printer_req );
/* Check if the request was successfully executed: */
if( error )
printf( "Problems while printing!" );
/* Clean up and quit: */
clean_up( "The End!" );
}
/* Close and return everything that has been */
/* opened and allocated before we quit: */
void clean_up( STRPTR text )
{
/* Close the Printer Device: */
if( !printer_dever )
CloseDevice( printer_req );
/* Deallocate the printer request block: */
if( printer_req )
DeleteExtIO( printer_req, sizeof(union printerIO) );
/* Remove the replyport: */
if( replymp )
DeletePort( replymp);
/* Print the message: */
printf( "\n%s\n", text );
/* Quit: */
exit( 0 );
}
9.4 OTHER USEFUL COMMANDS
There exist four more printer request commands that may
sometimes be useful:
1. Flush, removes all queued requests.
2. Reset, reinitializes the printer device.
3. Start, restarts the printer communication.
4. Stop, temporary stops the printer communication.
9.4.1 FLUSH
If several requests are sent to the printer device they are
all queued on a FIFO (First In First Out) basis. The command
"CMD_FLUSH" can then be used to remove all these queued
commands. Here is an example:
/* We want to remove all queued requests: */
printer_req->ios.io_Command = CMD_FLUSH;
/* Do our request: */
error = DoIO( printer_req );
/* OK? */
if( error )
printf( "Could not remove the queued requests!\n" );
9.4.2 RESET
Send the command "CMD_RESET" to reset the printer device. All
commands that are queued to the device will be removed, the
command that is currently executed will be aborted, and all
printer flags are resetted. Here is an example:
/* We want to reset the printer device: */
printer_req->ios.io_Command = CMD_RESET;
/* Do our request: */
error = DoIO( printer_req );
/* OK? */
if( error )
printf( "Could not reset the printer device!\n" );
9.4.3 START
After you have stopped the printer communication by sending an
CMD_STOP command, you may want to start the communication again.
It is done by sending a CMD_START command. Here is an example:
/* We want to start printer communication again: */
printer_req->ios.io_Command = CMD_START;
/* Do our request: */
error = DoIO( printer_req );
/* OK? */
if( error )
printf( "Could not restart the printer communication!\n" );
9.4.4 STOP
To temporary stop all printer communication you send a CMD_STOP
command. The communication will then first start again when a
CMD_START command is broadcasted. Here is an example:
/* We want to temporary stop all printer communication: */
printer_req->ios.io_Command = CMD_STOP;
/* Do our request: */
error = DoIO( printer_req );
/* OK? */
if( error )
printf( "Could not stop the printer communication!\n" );
9.5 FUNCTIONS
DoIO()
DoIO() is used to send requests to a device, and waits for it
to be completed. While the program is waiting it is put to
sleep so it will not waste any computer time. DoIO() will
return first when the request have been completed or failed,
and no message is therefore sent to the reply port.
Synopsis: error = DoIO( req );
error: (long) DoIO() will return first when the request has
been completed or something has failed. If the
request was successfully completed zero is returned,
else an error number is returned. What error number
depends on which device was used.
req: (struct IORequest *) Pointer to the request you
want to have executed.
SendIO()
SendIO() is used to send requests to a device, but will
return immediately without any delay. To check if the request
have been completed use the CheckIO() function, or look
at the request's reply port for any messages. Once the
request has been completed you must remove the message at
the reply port. (CheckIO() will not do it.) To remove a
message use the function Remove(). Note that you may NOT
close the device before all requests have been completed
or aborted!
Synopsis: SendIO( req )
req: (struct IORequest *) Pointer to the request you
want to have executed.
CheckIO()
CheckIO() is used to check if a previously started request
has been completed. Note that this function will not remove
the message at the reply port. This must be done with the
Remove() function.
Synopsis: ptr = CheckIO( req );
ptr: (long) CheckIO() will either return NULL if the
request have not been completed or it will return a
pointer to the request block.
req: (struct IORequest *) Pointer to the request you
want to check.
WaitIO()
WaitIO() will wait for the request to be completed, and while
the program is waiting it is put to sleep so no computer time
is wasted.
Synopsis: error = WaitIO( req );
error: (long) WaitIO() will return first when the request,
that has previously been sent, has been completed or
something has failed. If the request was successfully
completed zero is returned, else an error number is
returned. What error number depends on which device
was used.
req: (struct IORequest *) Pointer to the request you
want to wait for to be completed. Note that the
request must have already been sent to the device
by either a SendIO() or BeginIO() function call.
AbortIO()
AbortIO() will try to abort a previously started request. This
function should be used sparsely since it does not look so
good if you start a request and the try to stop it. (Better
not start it at all.) However, it is easy, and can sometimes
be very useful.
A request that is aborted will have its io_Error field set
to IOERR_ABORTED (defined in header file "exec/errors.h").
Synopsis: AbortIO( req )
req: (struct IORequest *) Pointer to the request you
want to abort.
CloseDevice()
CloseDevice() will close a device. Note that you should NOT
close the device before all started asynchronous requests
have either been completed or aborted.
Synopsis: CloseDevice( ioreq );
ioreg: (struct IORequest *) Pointer to the device's
request block.
OpenDevice()
OpenDevice() will try to open the specified device.
Synopsis: error = OpenDevice( name, unit, req, flags );
error: (long) If OpenDevice() managed to open the device
it returns 0, else an error number is returned.
name: (char *) Name of the device you want to open.
The name of the printer device is
"printer.device".
unit: (long) Set this field to 0.
req: (struct IORequest *) Pointer to an already
initialized printerIO union.
flags: (long) Set this field to 0.
9.6 COMMANDS
Here is a complete list of commands you may send to the
printer device. For full documentation se examples above.
The special printer device commands: (Defined in header file
"devices/printer.h")
PRD_RAWWRITE Send untranslated characters to the printer.
PRD_PRTCOMMAND Send a printer command.
PRD_DUMPRPORT Print graphics. (Dump a RastPort to the
printer.)
The rest of the commands you may use are normal exec commands,
and are defined in header file "exec/io.h".
CMD_RESET Resets all parameters of the printer device.
CMD_WRITE Send data to the printer (through preferences).
CMD_STOP Temporary stops all printer communication.
CMD_START Restarts printer communication.
CMD_FLUSH Removes all queued requests.
9.7 EXAMPLES
Example 1
This program demonstrates how you can use the Printer
Device to send (raw as well as translated) text to a
printer.
Example 2
This program demonstrates how you can use the Printer
Device to send (raw as well as translated) text to a
printer. However, instead of waiting for our request to
be completed as in Example 1, we use asynchronous
requests.
Example 3
This program demonstrates how you can send printer commands to
the Printer Device, which will translate these commands with
help of Preferences, before they are sent to the printer.
Example 4
This example demonstrates how you can print graphics.
It will dump the workbench's Rastport to the printer.